#include "rpc.h"
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

rpc_data *add2_i8(rpc_data *);
rpc_data *error_case(rpc_data *in);
rpc_data *reverse_string(rpc_data *in);

int main(int argc, char *argv[]) {
    rpc_server *state;

    state = rpc_init_server(atoi(argv[1]));
    if (state == NULL) {
        fprintf(stderr, "Failed to init\n");
        exit(EXIT_FAILURE);
    }

    if (rpc_register(state, "add2", add2_i8) == -1) {
        fprintf(stderr, "Failed to register add2\n");
        exit(EXIT_FAILURE);
    }

    if (rpc_register(state, "error", error_case) == -1) {
        fprintf(stderr, "Failed to register error\n");
        exit(EXIT_FAILURE);
    }

    if (rpc_register(state, "reverse", reverse_string) == -1) {
        fprintf(stderr, "Failed to register reverse\n");
        exit(EXIT_FAILURE);
    }

    rpc_serve_all(state);

    return 0;
}

/* Adds 2 signed 8 bit numbers */
/* Uses data1 for left operand, data2 for right operand */
rpc_data *add2_i8(rpc_data *in) {
    /* Check data2 */
    if (in->data2 == NULL || in->data2_len != 1) {
        return NULL;
    }

    /* Parse request */
    char n1 = in->data1;
    char n2 = ((char *)in->data2)[0];

    /* Perform calculation */
    printf("add2: arguments %d and %d\n", n1, n2);
    int res = n1 + n2;

    /* Prepare response */
    rpc_data *out = malloc(sizeof(rpc_data));
    assert(out != NULL);
    out->data1 = res;
    out->data2_len = 0;
    out->data2 = NULL;
    return out;
}

rpc_data *error_case(rpc_data *in) {
    return NULL;
}

rpc_data *reverse_string(rpc_data *in) {
    char* str = (char*)(in->data2);
    char* new_str = (char*)malloc(strlen(str) + 1);
    
    for(int i=0; i<strlen(str); i++) {
        new_str[i] = str[strlen(str) - 1 - i];
    }
    new_str[strlen(str)] = 0;
    printf("raw string is    : %s\n", str);
    printf("reverse string is: %s\n", new_str);

    rpc_data *out = malloc(sizeof(rpc_data));
    assert(out != NULL);
    out->data1 = 0;
    out->data2_len = strlen(new_str) + 1;
    out->data2 = new_str;
    return out;
}
